<?php
if (! defined('IN_SITE')) {
	exit('invalid request');
}

/**
 * 缓存工具。
 */

class Cache {
	private static $redis;
	static private function getRedis()
	{
		if (!isset(self::$redis)) {
			self::$redis = new Redis();
			self::$redis->pconnect('127.0.0.1', 6379);
		}
		return self::$redis;
	}

	/**
	 * 从缓存中读取指定的键值。
	 * 如果指定的键值不存在，而且缺省值有效，则把缺省值写入缓存。
	 *
	 * 可以定义回调函数来指定缺省值，典型用法如下：
	 *
	 *		$now = time();
	 *		$value = Cache::get('key', function() use ($now){
	 *			return $now;
	 *		}, 10);
	 *		var_dump($value);
	 *
	 * @param string $key 键。
	 * @param string $def 缺省值，如果是 callable 则调用该函数获取缺省值。
	 * @param number $life 缺省值写入缓存时指定的有效期。
	 * @return string 返回的有效值为字符串，否则为 null。
	 */
	static public function get($key, $def = null, $life = 3600)
	{
		// 从缓存中读出目标值
		$redis = self::getRedis();
		$value = $redis->get($key);

		if ($value === false) {
			if (is_callable($def)) {
				// 调用回调函数获取缺省值
				$value = $def();
			} else {
				// 直接使用缺省值
				$value = $def;
			}
			if (isset($value)) {
				// 如果缺省值不为空，则写入缓存
				$value = self::put($key, $value, $life);
			}
		}
		return $value;
	}

	/**
	 * 把指定的键值写入缓存。
	 *
	 * @param string $key 键。
	 * @param string/mixed $value 值，如果传入值不是字符串的话，则实际写入的是 json 编码格式。
	 * @param number $life 缓存有效期。
	 * @return string 实际写入缓存的值。
	 */
	static public function put($key, $value, $life = 3600)
	{
		if (!isset($value)) {
			// 如果值为空，则按删除处理
			self::delete($key);
			return null;
		}
		if (!is_string($value)) {
			// 如果值不是字符串，则先用 json 编码
			$value = json_encode($value);
		}
		$life = intval($life);

		$redis = self::getRedis();
		if ($life > 0) {
			$redis->setex($key, $life, $value);
		} else {
			$redis->set($key, $value);
		}
		return $value;
	}

	/**
	 * 删除键值。
	 * @param string $key 键。
	 * @return number 删除成功返回 1，否则为 0。
	 */
	static public function delete($key)
	{
		$redis = self::getRedis();
		return $redis->delete($key);
	}
}
